package damai.web;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.yc.damai.entity.DmAddress;
import com.yc.damai.entity.DmOrderitem;
import com.yc.damai.entity.DmOrders;
import com.yc.damai.entity.DmProduct;
import com.yc.damai.mapper.DmAddressMapper;
import com.yc.damai.mapper.DmOrderitemMapper;
import com.yc.damai.mapper.DmOrdersMapper;
import com.yc.damai.mapper.DmProductMapper;
import com.yc.damai.vo.Result;
import damai.web.feign.UserDo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

@RestController
public class OrderDo {

    @Resource
    private DmOrdersMapper ordersMapper;
    @Resource
    private DmOrderitemMapper orderitemMapper;
    @Resource
    private DmProductMapper productMapper;

    @Transactional
    @RequestMapping("commit")
    public Result commit(DmOrders order, List<DmOrderitem> items) {
        // TODO 省略业务层
        if (order.getUid() == null) {
            return new Result(-1, "请先登录系统", null);
        }
        if (order.getAid() == null) {
            return new Result(-2, "请选择收货地址", null);
        }
        ordersMapper.insert(order);
        final double[] sum = {0};
        items.forEach(item -> {
            final DmProduct product = productMapper.selectById(item.getPid());
            if (product.getStore() - item.getCount() < 0) {
                throw new RuntimeException(product.getPname() + "库存不足!");
                // 思考: 抛出异常的后续处理 :)
            } else {
                // 修改商品数量
                product.setStore(product.getStore() - item.getCount());
                productMapper.updateById(product);
            }
            // 设值订单外键
            item.setOid(order.getId());
            // 计算当前商品金额
            item.setTotal(product.getShopPrice() * item.getCount());
            // 计算订单金额
            sum[0] += item.getTotal();
            //  新增订单明细
            orderitemMapper.insert(item);
        });
        order.setTotal(sum[0]);
        order.setState(1);
        ordersMapper.updateById(order);
        return new Result(1, "订单提交成功", null);
    }

    // Redis + RabbitMQ

    private Date dacuBegin;
    private Date dacuEnd;
    @Resource
    private RedisTemplate redisTemplate;

    @RequestMapping("dacu/begin")
    public String begin(@RequestParam(defaultValue = "1") int times) {
        this.dacuBegin = new Date();
        this.dacuEnd = new Date(dacuBegin.getTime() + times * 60 * 60 * 1000);

        // 查询大促商品, 存入redis
        LambdaQueryWrapper<DmProduct> lqw = new LambdaQueryWrapper<>();
        lqw.le(DmProduct::getId, 20);
        final List<DmProduct> list = productMapper.selectList(lqw);
        list.forEach(p -> {
            final ValueOperations ops = redisTemplate.opsForValue();
            ops.set("p_" + p.getId(), p);
        });
        return "大促开始, 截止时间:" + dacuEnd;
    }

    @RequestMapping("dacu/query")
    public List<DmProduct> queryDacu() {
        List<DmProduct> list = new ArrayList<>();
        final ValueOperations ops = redisTemplate.opsForValue();
        final Set keys = redisTemplate.keys("p_*");
        keys.forEach(key -> {
            DmProduct p = (DmProduct) ops.get(key);
            list.add(p);
        });
        return list;
    }

    @RequestMapping("dacu/times")
    public Map<String, Object> getTime() {
        // dacuBegin 为空, 大促未开始
        if (dacuBegin == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("begin", dacuBegin.getTime());
        map.put("end", dacuEnd.getTime());
        return map;
    }

    @Resource
    RabbitTemplate rabbitTemplate;

    @Resource
    UserDo userDo;

    @Resource
    DmAddressMapper addressMapper;

    @RequestMapping("dacu/seckill")
    public Result seckill(int pid) {

        if (dacuBegin == null) {
            return new Result(-3, "秒杀活动未开始!", pid);
        }

        final ValueOperations ops = redisTemplate.opsForValue();
        DmProduct p = (DmProduct) ops.get("p_" + pid);
        if (p == null) {
            return new Result(-1, "该商品不是促销商品", pid);
        }
        if (p.getStore() == 0) {
            return new Result(-2, "该商品已经售罄!", pid);
        }
        p.setStore(p.getStore() - 1);
        ops.set("p_" + pid, p);

        // TODO 先暂时用硬编码, 提交用户数据
        Result res = userDo.myinfo();
        if (res.getCode() != 1) {
            return new Result(-4, "请求先登录系统!", pid);
        }
        Map<String, Object> myinfo = (Map<String, Object>) res.getData();
        Integer uid = Integer.parseInt(myinfo.get("id") + "");
        // 查询用户的收货地址
        LambdaQueryWrapper<DmAddress> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DmAddress::getUid, uid);
        final List<DmAddress> addressList = addressMapper.selectList(lqw);
        if(addressList.isEmpty()){
            return new Result(-5, "请添加一个收货地址!", pid);
        }
        int aid = addressList.get(0).getId();

        DmOrders orders = new DmOrders();
        orders.setUid(uid);
        orders.setAid(aid);

        List<DmOrderitem> items = new ArrayList<>();
        DmOrderitem doi = new DmOrderitem();
        doi.setPid(pid);
        doi.setCount(1);
        items.add(doi);

        OrderMsg msg = new OrderMsg(orders, items);
        rabbitTemplate.convertAndSend("dacu.Queue", msg);
        return new Result(1, "订单已经受理!", null);
    }

    @RabbitListener(queuesToDeclare = @Queue("dacu.Queue"))
    public void commit(OrderMsg msg) {
        commit(msg.orders, msg.items);
    }

}

@Data
@NoArgsConstructor
@AllArgsConstructor
class OrderMsg implements java.io.Serializable {
    DmOrders orders;
    List<DmOrderitem> items;
}
